<?php

class Model
{

    public $table; //默认操作table
    public $id; //默认id
    public $order_id = false; //默认优先排序
    public $db_link = 'db';

    /**
     * 增加一条数据到对应table
     * 
     * @param array，关联数组，对应table里的字段 
     * @return int 新增数据的id
     */
    public function add($data = array())
    {
        $table = $this->table;
        //if(isset($data['table']))unset($data['table']);
        $param = array();
        $sql = $this->make_insert_sql($table, $data, $param);
        $db = Database::getInstance($this->db_link);

        if ($db->run($sql, $param))
        {
            $id = $db->getInsertId();
            if ($id)
                $this->afterAdd($id, $data);
            return $id;
        } else
        {
            return false;
        }
    }

    /**
     * 执行一条SQL语句
     * 
     * @param string SQL语句
     * @return bool 是否执行成功
     */
    public function run_sql($sql, $param = array())
    {
        $db = Database::getInstance($this->db_link);
        return ($db->run($sql, $param));
    }

    /**
     * 删除一条数据
     * 
     * @param int id
     * @return bool 是否删除成功
     */
    public function delete($id)
    {
        $sql = "DELETE FROM $this->table WHERE $this->id = ? limit 1";
        $db = Database::getInstance($this->db_link);
        $param = array($id);
        $r = ($db->run($sql, $param));
        if ($r)
            $this->afterDelete($id);

        return $r;
    }

    /**
     * 根据传入id，更新数据
     * 
     * @param  int，欲更新数据的id; array 关联数组，新的数据，对应table的字段
     * @return bool 是否更新成功
     */
    function update($id, $data = array())
    {
        $db = Database::getInstance($this->db_link);
        $table = isset($data['table']) ? $data['table'] : $this->table;
        unset($data['table']);
        $param = array();
        $sql = $this->make_update_sql($table, $data, array($this->id => $id), $param);
        $r = ($db->run($sql, $param));
        if ($r)
            $this->afterUpdate($id, $data);

        return $r;
    }

    /**
     * 检查table中是否存在相同数据
     * 
     * @param  array 关联数组，新的数据，对应table的字段
     * @return bool 是否找到
     */
    public function exists($data)
    {
        $data['select'] = 'count(1) as total';
        $r = $this->get_one($data);
        return intval($r['total']) > 0;
    }

    /**
     * 获得table中的一条数据
     * 
     * @param  int 或者 array， id 或者 关联数组
     * @return array 关联数组
     */
    public function get_one($id)
    {
        $db = Database::getInstance($this->db_link);
        if (is_array($id)) // if by condition
        {
            $id['total'] = '1';
            $arr = $this->get_list($id);
            return is_array($arr) && count($arr) > 0 ? $arr[0] : array();
        } else
        {
            return $db->queryOne("SELECT * FROM $this->table WHERE $this->id = ? limit 1", $id);
        }
    }

    /**
     * 获得table中的一条数据
     * 
     * @param  int 或者 array， id 或者 关联数组
     * @param  string ,返回对应的值
     * @return string 对应的值
     */
    public function get_value($id, $key)
    {
        $arr = $this->get_one($id);
        return $arr[$key];
    }

    /**
     * 获得table中的多行数据数据
     * 
     * @param array， 关联数组 对应table中的字段。但是除了 select,table,where,order,total,from这几个特殊的 值。
     * @param array['select'] string 可选，用于构建 select * from 部分的 * ，默认为*
     * @param array['table'] string 可选，用于构建 select * from table 部分的 table ，默认为 $this->table
     * @param array['where'] string 可选，其值将直接用于构建 where 部分。比如 where name like '%a%' 部分的 name like '%a%'
     * @param array['order'] string 可选，其值将直接用于构建 order by 部分，比如 order by create_at desc 中的 create_at desc，默认为 $this->order_id desc,$this->id desc(如果定义了$this->order_id，否则为 $this->id desc)
     * @param array['total'] int 可选，用于构建 limit 部分。比如 limit 1 部分的 1
     * @param array['from'] int 可选，若定义了from那么必须定义total，二者用于构建 limit from,total。比如 limit 100,10 部分的 100
     * @return array 关联数组
     */
    public function get_list($data = array())
    {
        $db = Database::getInstance($this->db_link);
        $sql = '';
        //select what
        $_select = isset($data['select']) ? $data['select'] : '*';
        $_table = isset($data['table']) ? $data['table'] : $this->table;

        //user defined conditions such as `name` LIKE '%xxx%' ....
        if (isset($data['where']))
            $sql .= " AND " . $data['where'];

        //order control
        if (!isset($data['order']) && $this->order_id)
            $sql .= " ORDER BY $this->order_id DESC";
        else
            if (isset($data['order']) && $data['order'])
                $sql .= " ORDER BY " . $data['order'] . '';
            else
                $sql .= " ORDER BY $this->id DESC";

        //page control
        if (isset($data['from']) && isset($data['total']))
            $sql .= " LIMIT " . $data['from'] . "," . $data['total'];
        else
            if (isset($data['total']))
                $sql .= " LIMIT " . $data['total'];
        $sql .= ';';

        //unset control columns
        unset($data['select']);
        unset($data['table']);
        unset($data['where']);
        unset($data['order']);
        unset($data['total']);
        unset($data['from']);

        $param = array();
        $sql = $this->make_select_sql($_table, $data, $_select, $param) . $sql;
        return $db->_query($sql, $param);
    }

    private function make_insert_sql($table, $data, &$param)
    {
        $cols = array();
        $vals = array();
        $param = array();
        foreach ($data as $key => $val)
        {
            $cols[] = "`$key`";
            $vals[] = "?";
            $param[] = $val;
        }
        return "INSERT INTO $table (" . join(',', $cols) . ") VALUES(" . join(',', $vals) .
            ") ";
    }

    private function make_select_sql($table, $data = array(), $_select = '*', &$param)
    {
        $cond = array();
        $param = array();
        foreach ($data as $key => $val)
        {
            $cond[] = "`$key` = ? ";
            $param[] = $val;
        }
        $sql = "SELECT $_select FROM $table ";
        if (count($cond) > 0)
            $sql .= " WHERE " . join(' AND ', $cond);
        else
            $sql .= " WHERE 1=1 ";
        return $sql;
    }

    private function make_update_sql($table, $data, $cond_arr, &$param)
    {
        $values = array();
        $cond = array();
        $param = array();
        foreach ($data as $key => $val)
        {
            $values[] = "`$key` = ?";
            $param[] = $val;
        }
        foreach ($cond_arr as $key => $val)
        {
            $cond[] = "`$key` = ?";
            $param[] = $val;
        }
        return "UPDATE $table SET " . join(',', $values) . " WHERE " . join(' AND ', $cond);
    }


    public function afterAdd($id = null, $data = null)
    {

    }

    public function afterUpdate($id = null, $data = null)
    {

    }

    public function afterDelete($id = null)
    {

    }
}
